package design.leetCode1242_Solution2;

import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public class Solution {

    private final ConcurrentHashMap<String, String> visited = new ConcurrentHashMap<String, String>();

    private final LinkedBlockingQueue<String> wait_process_urls = new LinkedBlockingQueue<String>();
    private String domain = null;
    private AtomicInteger future_task_num = new AtomicInteger(0);

    private String getDomain(String url) {
        int end_idx = url.indexOf("/", 7);
        if (end_idx == -1) {
            end_idx = url.length();
        }
        return url.substring(7, end_idx);
    }

    public List<String> crawl(String startUrl, HtmlParser htmlParser) {
        int end_idx = startUrl.indexOf("/", 7);
        if (end_idx == -1) {
            end_idx = startUrl.length();
        }
        this.domain = startUrl.substring(7, end_idx);

        wait_process_urls.add(startUrl);


        while (future_task_num.get() > 0 || wait_process_urls.size() > 0) {
            String url = null;
            try {
                url = wait_process_urls.poll(1000, TimeUnit.MICROSECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (url == null) {
                continue;
            }


            visited.put(url, url);
            String finalUrl1 = url;

            AtomicInteger task_num = this.future_task_num;
            task_num.incrementAndGet();
            new Thread(() -> {
                try {
                    List<String> lst = htmlParser.getUrls(finalUrl1);
                    //System.out.println("ret from get, spend " + (System.currentTimeMillis() - start_time) + " ms");

                    if (lst != null) {
                        for (String new_url : lst) {
                            if ( !visited.containsKey(new_url) && domain.equals(getDomain(new_url)) ) {
                                wait_process_urls.add(new_url);
                                //System.out.println("add url " + new_url);
                            }
                        }
                    }

                } catch (Exception  e) {
                    e.printStackTrace();
                }

                task_num.decrementAndGet();
            }).start();
        }

        //System.out.println("over");
        return new ArrayList<String>(visited.keySet());
    }

    interface HtmlParser {
        // Return a list of all urls from a webpage of given url.
        // This is a blocking call, that means it will do HTTP request and return when this request is finished.
        public List<String> getUrls(String url);
    }
}
